import { Injectable, HttpException } from '@nestjs/common';
// import { HttpException } from '@nestjs/core';
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm';
import { Repository, EntityManager, In } from 'typeorm';
import { Users } from "../../entities/users.entity";
import { Role } from "../../entities/role.entity";
import { Permission } from "../../entities/permission.entity";
import { aesDecrypt, responseStatus } from "../../utils";
import { AuthService } from '../auth/auth.service';
import { RoleService } from '../roles/role.service';
@Injectable()
export class UsersService {
    constructor(
        @InjectEntityManager()
        private readonly entityManager: EntityManager,
        @InjectRepository(Users)
        private readonly usersRepository: Repository<Users>,
        @InjectRepository(Role)
        private readonly roleRepository: Repository<Role>,
        private readonly roleService: RoleService,
        private readonly authService: AuthService,
    ) { }
    private readonly cipher = '123456'
    private insertUserData = {
        avatar: '',
        username: '',
        cipher: '',
        password: '',
        email: '',
        status: null,
        administrator: false,
        roles: [],
        websiteId: null
    }
    async getAllUsers(data) {
        // return Promise.resolve(this.users);
        data.current = data.current || 1
        data.pageSize = data.pageSize || 10
        // console.log(data, 'asdada')
        // 1. 准备工作：注入Repository，创建queryBuilder
        // 条件筛选和分页查询代码
        let queryBy = this.usersRepository.createQueryBuilder('users')
        queryBy.leftJoinAndSelect('users.roles', 'role')
        // 2. 条件筛选查询，如名称、类型等，传入对应字段即可
        // .where(data as Partial<Users>)
        const { current = 1, pageSize = 10, status, roleIds, ...otherParams } = data;
        if (status) {
            queryBy.andWhere('users.status=:status').setParameter('status', status);
        } else if (roleIds) {
          queryBy.andWhere('role.id in(:id)', { id: roleIds.split(',') });
        } else {
            ['username', 'email'].forEach(key => {
              otherParams[key] && queryBy
                .andWhere(`users.${key} LIKE :${key}`)
                .setParameter(`${key}`, `%${otherParams[key]}%`);
            });
        }
        // 3. 时间范围筛选
        if (data && data['createTimeStart'] && data['createTimeEnd']) {
            queryBy = queryBy.andWhere('users.createTime BETWEEN :start AND :end', {
                start: data['createTimeStart'],
                end: data['createTimeEnd']
            })
        }

        // 普通排序
        queryBy = queryBy.orderBy('users.createTime', 'DESC')

        // 自定义条件，且多重排序
        // 例如：createTime字段为 ${data.start} 的优先显示,然后再在此基础上再进行时间和状态的排序
        queryBy = queryBy
            // .orderBy(`case update_time when update_time="${data['order_by_update']}" then 1 else 0 end`)
            .addOrderBy('users.status', 'ASC')
            .addOrderBy('users.createTime', 'DESC')
        queryBy = queryBy
            .skip(pageSize * (current - 1))
            .take(pageSize)

        /* 其中限制获取的条数，用 take 和 limit 都可以，官方给出的文档说明
        take: 
            * Sets maximal number of entities to take.
        limit:     
            * Set's LIMIT - maximum number of rows to be selected.
            * NOTE that it may not work as you expect if you are using joins.
            * If you want to implement pagination, and you are having join in your query,
            * then use instead take method instead.
        因此限制返回条数的话，首先考虑使用take，limit 是 take 的功能子集
        */
        // 5. 获取结果及(非分页的)查询结果总数
        // 或使用 .getMany() 不会返回总数

        return await queryBy.getManyAndCount()
    }
    async login(data) {
        let { password } = data
        // password = decryptByDES(password);
        password = aesDecrypt(password, data.cipher)
        const loginUser = await this.entityManager.findOne('Users', {
            where: { username: data.username } as Users,
            relations: ['roles'],
        })
        const roleList: any = await this.roleService.findRolesByIds(loginUser.roles.map((el: Role) => el.id))
        let permissions: Permission[] = roleList.reduce((total: Permission[], current: Role) => {
            total = [...total, ...current.permissions]
            return total
        }, [])
        permissions = permissions.filter((el, index, self) => self.findIndex(_ => _.id === el.id) === index)
        if (!loginUser || loginUser.status + '' === '1002') throw new HttpException("该用户不存在或已被冻结，请联系管理员！", responseStatus.failed.code);
        if (loginUser.password !== password) throw new HttpException("用户名或密码错误,请重新输入！", responseStatus.failed.code);
        // console.log(permissions, 'permissions');
        return this.authService.signIn({ ...loginUser, permissions: permissions.map(el => el.code) })
    }
    async getUser(id: number): Promise<Users> {
        // console.log(id, 'userid')
        // const user = this.users.find((user) => user.id === id);
        if (!id) {
            throw new HttpException("用户名不存在！", 404);
        }
        // return Promise.resolve(user);
        const queryBy = await this.usersRepository.createQueryBuilder('users').andWhere('users.id=:id').setParameter('id', id)
        queryBy.leftJoinAndSelect('users.roles', 'role');
        return await queryBy.getOne()
        // else throw new HttpException("用户名不存在！", 404);
    }
    async register(user: Users) {
        if (!user) {
            throw new HttpException("参数为空", responseStatus.failed.code);
        }
        const hasUser = await this.usersRepository.findOne({ 'username': user.username })
        if (hasUser) {
            throw new HttpException("用户名已存在,请重新输入！", responseStatus.failed.code);
        } else {
            let data = { ...this.insertUserData }
            data.password = aesDecrypt(user.password, this.cipher)
            const isRightPwd = await this.usersRepository.findOne({ 'username': user.username, 'password': user.password })
            !isRightPwd && new HttpException("用户名或密码错误,请重新输入！", responseStatus.failed.code)
            data.avatar = user.avatar
            data.cipher = user.password
            data.username = user.username
            data.email = user.email
            if (user.roles && user.roles.length) {
                let roles = await this.roleRepository.find({id: In(user.roles) })
                data.roles = roles
            }
            await this.usersRepository.save(data)
            return responseStatus.success.message
        }
    }
    async editUser(user: Users) {
        if (!user) {
            throw new HttpException("参数为空", responseStatus.failed.code);
        }
        let existUser = await this.usersRepository.findOne({ id: user.id })
        // console.log(hasUser)
        if (!existUser) {
            throw new HttpException("用户名不存在！", responseStatus.failed.code);
        } else {
            let data = {
                ...this.insertUserData,
                cipher: existUser.cipher,
                administrator: existUser.administrator,
                password: existUser.password
            }
            if (user.password) {
                data.cipher = user.password
                data.password = aesDecrypt(user.password, this.cipher)
            }
            data.avatar = user.avatar
            data.username = user.username
            data.email = user.email
            data.status = user.status
            data.websiteId = user.websiteId || existUser.websiteId || null
            if (user.roles && user.roles.length) {
                let roles = await this.roleRepository.find({id: In(user.roles) })
                data.roles = roles
            }
            const updatedUser = { ...existUser, ...data }
            await this.usersRepository.save(updatedUser)
            return responseStatus.success.message
        }
    }
    async delete(id) {
        // user.id = this.users.length + 1
        // this.users.push(user);
        // return Promise.resolve('操作成功！');
        if (!id) {
            throw new HttpException("参数为空", responseStatus.failed.code);
        }
        const hasUser = await this.usersRepository.findOne({ id })
        // console.log(hasUser)
        if (!hasUser) {
            throw new HttpException("用户不存在！", responseStatus.failed.code);
        } else {
            await this.usersRepository.remove(hasUser)
            return responseStatus.success.message
        }
    }
    async setStatus({ id, status }) {
        if (!id || !status) {
            throw new HttpException("参数为空", responseStatus.failed.code);
        }
        let existUser = await this.usersRepository.findOne({ id })
        // console.log(hasUser)
        if (!existUser) {
            throw new HttpException("用户不存在！", responseStatus.failed.code);
        }
        const updatedUser = { ...existUser, status }
        await this.usersRepository.save(updatedUser)
        return responseStatus.success.message
    }
    async setWebsiteId({ id, websiteId }) {
        if (!id || !websiteId) {
            throw new HttpException("参数为空", responseStatus.failed.code);
        }
        let existUser = await this.usersRepository.findOne({ id })
        // console.log(hasUser)
        if (!existUser) {
            throw new HttpException("用户不存在！", responseStatus.failed.code);
        }
        const updatedUser = { ...existUser, websiteId }
        await this.usersRepository.save(updatedUser)
        return responseStatus.success.message
    }
}